﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LabMonitorRemote;
using System.Threading;
using System.Net.NetworkInformation;

namespace LabMonitorRemote
{
    public partial class frmMain : Form
    {
        Int32 _DataPacketSize;

        DateTime _DownloadFromDate = DateTime.Now.AddDays(-1);
        DateTime _DownloadThroughDate = DateTime.Now.AddDays(-1);

        List<LoggerDownload> loggerDownloadList = new List<LoggerDownload>();
        List<CommFeedbackUserControl> LoggerFeedbackControlList = new List<CommFeedbackUserControl>();
        List<DewkLogger> _loggerList = new List<DewkLogger>();
        List<DewkPing> pingList = new List<DewkPing>();
        Boolean _WriteByteStreams;
        Boolean _ActiveMonitoringRunning;
        Boolean _AutomaticDownloadEnabled;
        DateTime _DailyDownloadTime;
        String _DownloadFolder;
        System.Threading.Timer _AutomaticDownloadTimer;
        System.Threading.Timer _ActiveMonitoringTimer;  

        public frmMain()
        {
            InitializeComponent();
        }

        private Boolean WriteByteStreams
        {
            get { return _WriteByteStreams;}
            set 
            {
                if (_WriteByteStreams != value)
                {
                    _WriteByteStreams = value;
                }
            }
        }

        private Boolean ActiveMonitoringRunning
        {
            get { return _ActiveMonitoringRunning; }
            set 
            { 
                if (_ActiveMonitoringRunning != value)
                _ActiveMonitoringRunning = value; 
            }
        }

        private void ExitApplication()
        {
            this.Close();
        }
        
        private void frmMain_Load(object sender, EventArgs e)
        {
            flbCommunicationFeedback.AutoScroll = true;

            dtpDownloadFrom.Value = _DownloadFromDate;
            dtpDownloadThrough.Value = _DownloadThroughDate;

            ReLoadLoggers();
            BuildLoggerMenuItems();

            lblCommFeedbackClear.Text = "";

            // Auto Download Settings
            ReLoadDailyDownloadSettings();
            SetActiveDownloadTimer();
        }

        private void ReLoadDailyDownloadSettings()
        {
            _AutomaticDownloadEnabled = Properties.Settings.Default.EnableDailyDownload;
            _DailyDownloadTime = Properties.Settings.Default.DailyDownloadTime;
            _DownloadFolder = Properties.Settings.Default.DownloadFolder;
            _DataPacketSize = Properties.Settings.Default.DownloadPacketSize;
        }

        private void BuildLoggerMenuItems()
        {
            ToolStripMenuItem[] loggers = new ToolStripMenuItem[_loggerList.Count];
            for (int i = 0; i < loggers.Length; i++)
            {
                loggers[i] = new ToolStripMenuItem();
                loggers[i].Name = _loggerList[i].IpAddress;
                loggers[i].Tag = string.Format("http://{0}", _loggerList[i].IpAddress);
                loggers[i].Text = string.Format("{0} HTML Page", _loggerList[i].LoggerName);
                loggers[i].Click += new EventHandler(MenuItemClickEventHandler);
            }

            //menuStrip.Items.AddRange(loggers);
            ToolStripMenuItem loggerDD = (ToolStripMenuItem)menuStrip.Items[2];
            loggerDD.DropDownItems.AddRange(loggers);
        }
        private void MenuItemClickEventHandler(object sender, EventArgs e)
        {
            ToolStripMenuItem clickedItem = (ToolStripMenuItem)sender;
            System.Diagnostics.Process.Start(clickedItem.Tag.ToString());
        }

        private void ClearControls()
        {
            this.Invoke((Action)delegate
            {
                flbCommunicationFeedback.Controls.Clear();
            });
            }

        private void ClearLoggerDownloadLists()
        {
            for (Int32 i = 0; i < loggerDownloadList.Count; i++)
            {
                loggerDownloadList[i] = null;
            }
            while (loggerDownloadList.Count > 0)
            {
                loggerDownloadList.RemoveAt(0);
            }
            loggerDownloadList.Clear();
        }


        private void ReLoadLoggers()
        {

            _loggerList.Clear();

            using (var db = new LMRDataContext())
            {
                var loggers = from range in db.GetTable<SavedLogger>()
                              select range; //db.SavedLoggers.Take(9);

                foreach (var l in loggers)
                {
                    _loggerList.Add(new DewkLogger(
                        l.LoggerName,
                        l.LoggerDescription,
                        l.LoggerIpAddress,
                        (Boolean)l.DisplayF,
                        (Int32)l.RecInterval,
                        (DateTime)l.LastDownloadedThrough, // error if null from database
                        (Boolean)l.Ch1Enabled,
                        (double)l.Ch1TempHigh,
                        (double)l.Ch1TempLow,
                        (double)l.Ch1HumidHigh,
                        (double)l.Ch1HumidLow,
                        (Boolean)l.Ch2Enabled,
                        (double)l.Ch2TempHigh,
                        (double)l.Ch2TempLow,
                        (double)l.Ch2HumidHigh,
                        (double)l.Ch2HumidLow,
                        (Int32)l.ID));
                }

            }    
            clbLoggerList.Items.Clear();
            foreach (DewkLogger dewk in _loggerList)
                clbLoggerList.Items.Add(dewk.LoggerName);
            
        }

        private void btnDownload_Click(object sender, EventArgs e)
        {

            Boolean netActivity = false;
            foreach (CommFeedbackUserControl c in LoggerFeedbackControlList)
            {
                if (c.LoggerCommunicationActive())
                {
                    netActivity = true;
                }
            }
            // CHECK FOR EXISTING NETWORK ACTIVITY BEFORE STARTING DOWNLOADS
            if (!netActivity)
            {
                ClearLoggerDownloadLists();
                ClearControls();
                PopulateDownloadList(); // This will initiaite the downloads
            }
            else
            {
                lblCommFeedbackClear.Text = "Please wait, active comm in session";
                lblCommFeedbackClear.ForeColor = Color.Red;
                
                // start thread to clear the label 
                Thread thread = new Thread(this.ClearLabel);
                thread.Start();
            } // END NETWORK ACTIVITY CHECK
            
        }

        private void PopulateDownloadList()
        {
            if (clbLoggerList.CheckedItems.Count != 0)
            {
                for (Int32 i = 0; i < clbLoggerList.Items.Count; i++)
                {
                    if (clbLoggerList.GetItemChecked(i))
                    {
                        AddToDownloadList(_loggerList[i]);
                    }
                }
            }
        }

        private void AddToDownloadList(DewkLogger dewk, Boolean SinceLastDownload = false)
        {
            DateTime fromDate, throughDate;

            if (SinceLastDownload)
            {
                // Establish Dates
                fromDate = dewk.LastDownloadedThrough.AddDays(1);
                throughDate = DateTime.Now.AddDays(-1);           
            }
            else
            {
                // Use Main form dates
                fromDate = _DownloadFromDate;
                throughDate =_DownloadThroughDate;
            }
            LoggerDownload newDownload = new LoggerDownload(dewk, fromDate, throughDate, _DataPacketSize);
            newDownload.ParentForm = this;
            loggerDownloadList.Add(newDownload);
            ShowLoggerDownloadControl(newDownload);
            
            // Define New Thread and Initiate Download
            Thread nextDownload = new Thread(newDownload.InitiateDownload);
            nextDownload.Start();
        }

        private void ShowLoggerDownloadControl(LoggerDownload download)
        {
            LoggerDownloadUserControl downloadControl = new LoggerDownloadUserControl(download);
            LoggerFeedbackControlList.Add(downloadControl);
            this.Invoke((Action)delegate
            {
                flbCommunicationFeedback.Controls.Add(downloadControl);
            });
        }

       
        private void btnClearCommFeedback_Click(object sender, EventArgs e)
        {
            Boolean clear = TestForNetworkActivity();
        }

        private Boolean TestForNetworkActivity()
        {
            Boolean netActivity = false;
            //for (Int32 i = 0; i < flbCommunicationFeedback.Controls.Count; i++)
            foreach (CommFeedbackUserControl c in LoggerFeedbackControlList)
            {
                if (c.LoggerCommunicationActive())
                {
                    netActivity = true;
                }
            }
            if (!netActivity)
            {
                this.Invoke((Action)delegate
                {
                    flbCommunicationFeedback.Controls.Clear();
                });
            }
            else
            {
                this.Invoke((Action)delegate
                {
                lblCommFeedbackClear.Text = "Please wait, active comm in session";
                lblCommFeedbackClear.ForeColor = Color.Red;
                });
                Thread thread = new Thread(this.ClearLabel);
                thread.Start();
            }
            return netActivity;
        }

        private void ClearLabel()
        {
        Thread.Sleep(2000);
        lblCommFeedbackClear.Invoke((Action)delegate
            {               
            lblCommFeedbackClear.Text = "";
            });
        }

        public void WriteNetworkFeedback(string message)
        {
            txtNetworkActivity.Invoke((Action)delegate
            {
                txtNetworkActivity.AppendText(Environment.NewLine + message);
            });
        }

        public void WriteNetworkFeedback(string LoggerName, string message)
        {
            txtNetworkActivity.Invoke((Action)delegate
            {
                txtNetworkActivity.AppendText(Environment.NewLine + "SENDING TO " + LoggerName + " : " + message);
            });
        }

        public void WriteNetworkFeedback(string LoggerName, byte[] message, Int32 readLength)
        {
            if (WriteByteStreams)
            {
                string strMessage = "";

                for (Int32 i = 0; i < readLength; i++)
                {
                    strMessage += message[i].ToString() + " ";
                }
                this.Invoke((Action)delegate
                {
                    txtNetworkActivity.AppendText(Environment.NewLine + "REPLY FROM " + LoggerName + ": " + strMessage);
                });
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TerminateAllDownloads();
            if (!TestForNetworkActivity())
                ExitApplication();
        }

        private Boolean ValidateFromDate(DateTime newDate)
        {
            /* FROM DATE MUST:
             * 1) Be before to current date
             * 2) Occur before or equal to the THROUGH date
             */
            if (newDate < new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day)
                &&
                newDate <= _DownloadThroughDate)
            {
                return true;
            }
            else
            {
                double minus = -1;
                MessageBox.Show(string.Format("FROM DATE MUST\n1: Be before the current date\n2: Occur before THROUGH date"), "Invalid Date Selection");
                dtpDownloadFrom.Value = _DownloadThroughDate.AddDays(minus);
                return false;
            }            
        }

        private Boolean ValidateThroughDate(DateTime newDate)
        {
            /* THROUGH DATE MUST:
             * Occur before current date
             * Occur On or AFTER the FROM date
             */
            if (newDate < new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day)
                &&
                newDate >= _DownloadFromDate)
            {
                return true;
            }
            else
            {
                double minus = -1;
                MessageBox.Show(string.Format("THROUGH DATE MUST\n1: Be before the current date\n2: Occur after From date"), "Invalid Date Selection");
                dtpDownloadThrough.Value = DateTime.Now.AddDays(minus);
                return false;
            } 

        }

        private void SetFromDate(DateTime newDate)
        {
            if (ValidateFromDate(newDate))
                _DownloadFromDate = newDate;
        }

        private void SetThroughDate(DateTime newDate)
        {
            if (ValidateThroughDate(newDate))
                _DownloadThroughDate = newDate;
        }

        private void dtpDownloadFrom_ValueChanged(object sender, EventArgs e)
        {
            SetFromDate(dtpDownloadFrom.Value);
        }

        private void dtpDownloadThrough_ValueChanged(object sender, EventArgs e)
        {
            SetThroughDate(dtpDownloadThrough.Value);
        }

        
        private void chkSelectAll_CheckedChanged(object sender, EventArgs e)
        {
            
            if (chkSelectAll.Checked == true)
            {
                for (Int32 i = 0; i < clbLoggerList.Items.Count; i++)
                {
                    clbLoggerList.SetItemChecked(i, true);
                }
            }
            if (chkSelectAll.Checked == false)
            {
                for (Int32 i = 0; i < clbLoggerList.Items.Count; i++)
                {
                    clbLoggerList.SetItemChecked(i, false);
                }
            }
        }

        private void btnTestConnection_Click(object sender, EventArgs e)
        {
            BuildPingList();
        }

        #region TestConnections
        private void BuildPingList()
        {
            flbCommunicationFeedback.Controls.Clear();
            pingList.Clear();
            foreach (DewkLogger dewk in _loggerList)
            {
                DewkPing ping = new DewkPing(dewk, this);
                pingList.Add(ping);
                TestCommunicationUserControl dewkTestControl = new TestCommunicationUserControl(ping);
                
                this.Invoke((Action)delegate
                {
                    flbCommunicationFeedback.Controls.Add(dewkTestControl);
                });
            }
            TestLoggerConnections();
        }
        private void TestLoggerConnections()
        {
            foreach (DewkPing thisPing in pingList)
                {
                    Thread newThread = new Thread(thisPing.TestCommunications);
                    newThread.Start();
                }
        }
        #endregion TestConnections

        private void TerminateAllDownloads()
        {
            foreach (LoggerDownload download in loggerDownloadList)
                download.CancelDownload();
        }

        private void btnCancelAll_Click(object sender, EventArgs e)
        {
            TerminateAllDownloads();
        }

        private void chkShowByteStreams_CheckedChanged(object sender, EventArgs e)
        {
            if (chkShowByteStreams.Checked == true)
            {
                WriteByteStreams = true;
            }
            else
            {
                WriteByteStreams = false;
            }
        }

        private void btnClearNetworkActivity_Click(object sender, EventArgs e)
        {
            txtNetworkActivity.Clear();
        }

        private void SetActiveDownloadTimer()
        {
            DateTime now = DateTime.Now;
            DateTime nextDownloadDay = now.AddDays(1);
            var downloadTime = new DateTime(
                nextDownloadDay.Year,
                nextDownloadDay.Month, 
                nextDownloadDay.Day,
                Properties.Settings.Default.DailyDownloadTime.Hour,
                Properties.Settings.Default.DailyDownloadTime.Minute,
                Properties.Settings.Default.DailyDownloadTime.Second);
            _AutomaticDownloadTimer = new System.Threading.Timer(DownloadOnTimerCall, null, downloadTime - DateTime.Now, TimeSpan.FromMinutes(5));
        }

        private void DownloadOnTimerCall(object state)
        {
            
            while (TestForNetworkActivity())
            {
                Thread.Sleep(10000); // wait 10 seconds if network activity is already present
            }
            if (_AutomaticDownloadEnabled)
            {
                /*
                this.Invoke((Action)delegate
                {
                    flbCommunicationFeedback.Controls.Clear(); // Clear communication feedback box
                });
                */
                ClearLoggerDownloadLists();
                ClearControls();

                foreach (DewkLogger Dewk in _loggerList)
                {
                    AddToDownloadList(Dewk, true);
                }
            }
        }

        private void startActiveMonitorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!ActiveMonitoringRunning)
            {
                ActiveMonitoringRunning = true;
                
                // Start Timer
                _ActiveMonitoringTimer = new System.Threading.Timer(GetMeasurmentsOnTimerCall, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
                startActiveMonitorToolStripMenuItem.Text = "Stop Active Monitoring";
            }
            else
            {
                ActiveMonitoringRunning = false;
                _ActiveMonitoringTimer = null;  
                startActiveMonitorToolStripMenuItem.Text = "Start Active Monitoring";
                
                // clear feedback
                this.Invoke((Action)delegate
                {
                    flbCommunicationFeedback.Controls.Clear();
                });
            }
        }

        private void GetMeasurmentsOnTimerCall(object state)
        {
            while (TestForNetworkActivity() && ActiveMonitoringRunning)
            {
                Thread.Sleep(10000); // wait 10 seconds

            }

            if (ActiveMonitoringRunning)
            {
                this.Invoke((Action)delegate
                    {
                        flbCommunicationFeedback.Controls.Clear();
                    });

                foreach (DewkLogger dewk in _loggerList)
                {
                    DewkMeasurment newMeasurment = new DewkMeasurment(dewk, this);
                    DewkMeasurmentUserControl newMeasurmentControl = new DewkMeasurmentUserControl(newMeasurment, dewk);

                    this.Invoke((Action)delegate
                    {
                        flbCommunicationFeedback.Controls.Add(newMeasurmentControl);
                    });

                    Thread measurmentThread = new Thread(newMeasurment.GetCurrentMeasurment);
                    measurmentThread.Start();
                }
            }
        }

        private void manageThermohygrometersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmManageLoggers LoggersForm = new frmManageLoggers();
            LoggersForm.ShowDialog();
            if (Properties.Settings.Default.EnableDailyDownload)
            {
                DateTime nextDownloadDateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day + 1, Properties.Settings.Default.DailyDownloadTime.Hour, Properties.Settings.Default.DailyDownloadTime.Minute, Properties.Settings.Default.DailyDownloadTime.Second);
                string dailyDownloadReminder = string.Format("Automatic Downloads are turned ON.\nThe next scheduled download will occur:\n{0}\nPacket Size is set to {1} bytes", nextDownloadDateTime, Properties.Settings.Default.DownloadPacketSize);
                MessageBox.Show(dailyDownloadReminder,"Automatic Downloads: ON");
            }
            ReLoadDailyDownloadSettings();
            SetActiveDownloadTimer();
            ReLoadLoggers();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmAbout about = new frmAbout();
            about.ShowDialog();
        }

    } //CLASS frmMain
}// NAMESPACE LabMonitorRemote

